package app.species;

import sim.engine.*;
import sim.util.*;

public class Predator extends Entity{

	/**
	 * 
	 */
	private static final long serialVersionUID = 8102687098352781239L;

	private static double DEFAULT_RAND_VECT_LEN;

	private static double DEFAULT_DIAMETER = 75.0;
	private static double DEFAULT_SENSE_DIST = 75.0;
	private static double DEFAULT_SPEED = 10.0;
	private static int DEFAULT_LIFE_SPAN = 0;

	private static int energyAddedToCreature = -20;

	public Predator(MutableDouble2D initPos, MutableDouble2D initHead){

		super(initPos, initHead);

		this.setDiameter(Predator.DEFAULT_DIAMETER);
		this.setSenseDistance(Predator.DEFAULT_SENSE_DIST);
		this.setSpeed(Predator.DEFAULT_SPEED);
		this.setLifeSpan(Predator.DEFAULT_LIFE_SPAN);

		this.resetColor();

		this.setEnergy(Predator.energyAddedToCreature);

	}

	public Predator(){ super(); }

	public static void setDefaults(double diameter, double speed, double senseDist, int lifeSpan){

		Predator.DEFAULT_DIAMETER = diameter;
		Predator.DEFAULT_SPEED = speed;
		Predator.DEFAULT_SENSE_DIST = senseDist;
		Predator.DEFAULT_LIFE_SPAN = lifeSpan;

	}

	// this gives the amount of randomness added to the final vector
	public static void setRandomVectorLength(double d){

		Predator.DEFAULT_RAND_VECT_LEN = d;

	}

	public static void setEnergyAddedToCreature(int n){
		Predator.energyAddedToCreature = n;
	}

	/* simply updates the agent's position based off of its heading and current position
	 **/
	public void step(SimState state){

		SpeciesSim sim = (SpeciesSim)state;

		if(this.getAge() > this.getLifeSpan()){
			sim.removeEntityFromSim(this, sim.predators);
			return;
		}

		this.incrementAge();

		this.killCreatures(sim);
		this.moveTowardsCreatures(sim);

		// updates the heading of the entity if it is hitting a wall
		this.updateHeadingHitWall(sim.fieldWidth, sim.fieldHeight);

		/* update the position in the Continuous2D container
		 * also, update the position within the agent
		 **/
		this.updatePosition();
		sim.predators.setObjectLocation(this, new Double2D(this.position));

	}

	// kill nearby creatures
	private void killCreatures(SpeciesSim sim){

		Bag nearbyEntities = sim.creatures.getObjectsWithinDistance(new Double2D(this.position), this.getSenseDistance());
		Creature creature;

		for(int i = 0; i < nearbyEntities.numObjs; i++){

			creature = (Creature)nearbyEntities.objs[i];

			if(!creature.isAlive()) continue;

			// check to see if the creature is touching the food.  if it is, then eat the food and continue to next one
			if(this.isTouching(creature)){
				creature.addEnergy(this.getEnergy());
				continue;
			}

		}

	}

	/* moving food tries to avoid all creatures that it can currently see
	 * this updates the MovingFood's current heading
	 **/
	private void moveTowardsCreatures(SpeciesSim sim){

		Bag nearbyCreatures = sim.creatures.getObjectsWithinDistance(new Double2D(this.position), this.getSenseDistance());
		MutableDouble2D finalVector = new MutableDouble2D();
		MutableDouble2D randomVector;
		Creature creature;
		double dist, minDist;

		minDist = Double.MAX_VALUE;

		for(int i = 0; i < nearbyCreatures.numObjs; i++){

			creature = (Creature)nearbyCreatures.objs[i];

			dist = this.position.distance(creature.position);

			if(dist > 0.0 && dist - creature.getRadius() <= this.getSenseDistance() && dist < minDist){

				finalVector.subtract(creature.position, this.position);
				finalVector.normalize();

				minDist = dist;

			}

		}

		this.heading = finalVector;

		if(finalVector.lengthSq() > 0.0){

			// generate the random vector
			if(Predator.DEFAULT_RAND_VECT_LEN > 0.0){

				while(true){
					randomVector = new MutableDouble2D(sim.random.nextDouble() * Predator.DEFAULT_RAND_VECT_LEN, sim.random.nextDouble() * Predator.DEFAULT_RAND_VECT_LEN);
	
					if(randomVector.lengthSq() > 0.0 && randomVector.length() <= Predator.DEFAULT_RAND_VECT_LEN) break;
	
				}

				if(sim.random.nextBoolean()) randomVector.x *= -1.0;
				if(sim.random.nextBoolean()) randomVector.y *= -1.0;

				this.heading.normalize();

				this.heading.addIn(randomVector);

			}

			this.heading.normalize();
		}

	}

}
